package com.example.xcsubsystem.util;

import jakarta.annotation.Nonnull;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * 2024/9/30
 * SM4 加密工具
 * @author fengyu
 */
public class SM4CBCUtils {
    public static final String SM4 = "SM4";
    public static final String SM4_CBC_PADDING="SM4/CBC/PKCS5Padding";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密工具
     * 参数秘钥在代码中进行Base64的decode还原成 byte[16]
     * @param secretKey 秘钥是byte[16]经过Base64 encode后的字符串
     * @param iv 向量
     * @param decryptContext 要加密的文本
     * @return 密文字符串
     * @throws Exception
     */
    public static String encryptBySM4(@Nonnull String secretKey,
                                      byte[] iv,
                                      @Nonnull String decryptContext) throws Exception {
        if (null == iv) iv = new byte[16];
        Cipher cipher = generatecbccipher(Cipher.ENCRYPT_MODE, iv, Base64.getDecoder().decode(secretKey));
        byte[] bytes = cipher.doFinal(decryptContext.getBytes());
        byte[] ciphertext = Base64.getEncoder().encode(bytes);
        return new String(ciphertext, StandardCharsets.UTF_8);
    }

    /**
     * 解密工具
     * @param secretKey 秘钥是byte[16]经过Base64 encode后的字符串
     * @param iv 向量
     * @param decryptContext 要解密的文本
     * @return 原文本
     * @throws Exception
     */
    public static String decryptBySM4(String secretKey, byte[] iv, String decryptContext) throws Exception {
        if (null == iv) iv = new byte[16];
        byte[] decodedBytes = Base64.getDecoder().decode(decryptContext.getBytes(StandardCharsets.UTF_8));
        Cipher cipher = generatecbccipher(Cipher.DECRYPT_MODE, iv, Base64.getDecoder().decode(secretKey));
        byte[] bytes = cipher.doFinal(decodedBytes);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    private static Cipher generatecbccipher(int mode, byte[] iv, byte[] key) throws Exception {
        Key sm4Key = new SecretKeySpec(key, SM4);
        Cipher cipher = Cipher.getInstance(SM4_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
        IvParameterSpec ivParameterSpec =new IvParameterSpec(iv);
        cipher.init(mode, sm4Key, ivParameterSpec);
        return cipher;
    }

    public static byte[] generateIV(){
        byte[] ivBytes = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(ivBytes);
        return ivBytes;
    }

    /**
     * 生成秘钥
     * @return
     */
    public static String generateSecret() {
        byte[] bytes = new byte[16];
        new SecureRandom().nextBytes(bytes);
        return Base64.getEncoder().encodeToString(bytes);
    }
}
